#ifndef XG_REFLECT_H
#define XG_REFLECT_H
//////////////////////////////////////////////////////////////////////////////
#include "std.h"

typedef u_int64 ReflectKey;

#define first_tag(name, ...) name
#define first_str(name, ...) #name
#define first_args(name, ...) {__VA_ARGS__}
#define first_helper(name, ...) ReflectHelper __##name

#define reflect_object(type, ...)			\
type first_tag(__VA_ARGS__);				\
first_helper(__VA_ARGS__) = ReflectHelper(this, &this->first_tag(__VA_ARGS__), #type, first_str(__VA_ARGS__), first_args(__VA_ARGS__))

#define reflect_attr(type, defval, ...)		\
type first_tag(__VA_ARGS__) = defval;		\
first_helper(__VA_ARGS__) = ReflectHelper(this, &this->first_tag(__VA_ARGS__), #type, first_str(__VA_ARGS__), first_args(__VA_ARGS__))

#define rint(...) reflect_attr(int, 0, __VA_ARGS__)
#define rbool(...) reflect_attr(bool, false, __VA_ARGS__)
#define rlong(...) reflect_attr(long, false, __VA_ARGS__)
#define rfloat(...) reflect_attr(float, 0.0F, __VA_ARGS__)
#define rstring(...) reflect_attr(string, "", __VA_ARGS__)
#define rdouble(...) reflect_attr(double, 0.0, __VA_ARGS__)
#define robject(type, ...) reflect_object(type, __VA_ARGS__)

#define nint(...) rint(__VA_ARGS__, "optional")
#define nbool(...) rbool(__VA_ARGS__, "optional")
#define nlong(...) rlong(__VA_ARGS__, "optional")
#define nfloat(...) rfloat(__VA_ARGS__, "optional")
#define nstring(...) rstring(__VA_ARGS__, "optional")
#define ndouble(...) rdouble(__VA_ARGS__, "optional")
#define nobject(type, ...) robject(type, __VA_ARGS__, "optional")

class ReflectItem
{
	friend class JsonReflect;

protected:
	int offset;
	const char* name;
	const char* type;
	const char* remark;
	const char* extdata;

public:
	ReflectItem() : offset(0), type(NULL)
	{
	}
	ReflectItem(int _offset, const char* _type, const char* _name, const char* _remark, const char* _extdata) : offset(_offset), type(_type), name(_name), remark(_remark), extdata(_extdata)
	{
	}

public:
	bool operator < (const ReflectItem& obj) const
	{
		return offset < obj.offset;
	}
	bool operator == (const ReflectItem& obj) const
	{
		return offset == obj.offset;
	}

public:
	string get(const void* obj) const;
	bool set(void* obj, long val) const;
	bool set(void* obj, double val) const;
	bool set(void* obj, const char* val) const;

	bool canUse() const
	{
		return type ? true : false;
	}
	int getOffset() const
	{
		return offset;
	}
	const char* getName() const
	{
		return name;
	}
	const char* getType() const
	{
		return type;
	}
	const char* getRemark() const
	{
		return remark ? remark : "";
	}
	const char* getExtdata() const
	{
		return extdata ? extdata : "";
	}
	bool set(void* obj, int val) const
	{
		return set(obj, (long)(val));
	}
	bool set(void* obj, bool val) const
	{
		return set(obj, val ? 1 : 0);
	}
	bool set(void* obj, float val) const
	{
		return set(obj, (double)(val));
	}
	bool set(void* obj, const string& val) const
	{
		return set(obj, val.c_str());
	}
};

class ReflectHelper
{
public:
	static string GetAttrString(ReflectKey key);
	static vector<ReflectItem> GetAttrList(ReflectKey key);
	ReflectHelper(Object* self, void* data, const char* type, const char* name, const initializer_list<const char*>& list);
	ReflectHelper(Object* self, Object* data, const char* type, const char* name, const initializer_list<const char*>& list);

	static ReflectKey GetKey(const Object* obj)
	{
		return (ReflectKey)(typeid(*obj).name());
	}
	template<class REFLECT_TYPE> static ReflectKey GetKey()
	{
		return (ReflectKey)(typeid(REFLECT_TYPE).name());
	}

	static string GetAttrString(const Object* obj)
	{
		return GetAttrString(GetKey(obj));
	}
	template<class REFLECT_TYPE> static string GetAttrString()
	{
		string res = GetAttrString(GetKey<REFLECT_TYPE>());

		if (res.length() > 0) return res;

		REFLECT_TYPE item;

		return GetAttrString(&item);
	}

	static vector<ReflectItem> GetAttrList(const Object* obj)
	{
		return GetAttrList(GetKey(obj));
	}
	template<class REFLECT_TYPE> static vector<ReflectItem> GetAttrList()
	{
		vector<ReflectItem> vec = GetAttrList(GetKey<REFLECT_TYPE>());

		if (vec.size() > 0) return std::move(vec);

		REFLECT_TYPE item;

		return GetAttrList(&item);
	}
};
//////////////////////////////////////////////////////////////////////////////
#endif
